//
//  ITPingManager.m
//  InduceTool
//
//  Created by 魏延龙 on 2020/8/24.
//  Copyright © 2020 魏延龙. All rights reserved.
//

#import "ITPingManager.h"
#import <PPSPing/PPSPing.h>
@interface ITPingManager()<PPSPingDelegate>
{
    BOOL _hasStarted;
}

@property (nonatomic, copy)   NSString   *address;
@property (nonatomic, strong) PPSPing *ping;
@property (nonatomic, strong) NSTimer *timer;
//  发包次数，默认20个包
@property (nonatomic, assign) NSInteger  maximumPingTimes;

@property (nonatomic, strong) NSMutableArray *pingItems;
@property (nonatomic, assign) NSInteger holdNum;

// 默认 once
@property (nonatomic, assign) PingUseType pingUseType;
@property (nonatomic, assign) NSInteger timeoutCount;
@end

@implementation ITPingManager

+ (instancetype)serviceWithAddress:(NSString *)address {
    ITPingManager *services = [[ITPingManager alloc] initWithAddress:address];
    return services;
}

+(instancetype)serviceWithAddress:(NSString *)address maximumPingTimes:(NSInteger)count holdNum:(NSInteger)holdNum pingUseType:(PingUseType)pingUseType {
    ITPingManager *services = [[ITPingManager alloc] initWithAddress:address maximumPingTimes:count holdNum:holdNum pingUseType:pingUseType];
    return services;
}

- (instancetype)initWithAddress:(NSString *)address{
    self = [self initWithAddress:address maximumPingTimes:20 holdNum:8 pingUseType:PingUseTypeOnce];
    return self;
}

- (instancetype)initWithAddress:(NSString *)address maximumPingTimes:(NSInteger)maximumPingTimes holdNum:(NSInteger)holdNum pingUseType:(PingUseType)pingUseType{
    self = [super init];
    if (self) {
        _maximumPingTimes = maximumPingTimes;
        _holdNum = holdNum;
        _pingUseType = pingUseType;
        _address = [address copy];
        _ping = [PPSPing new];
        _ping.host = _address;
        _ping.delegate = self;
        _ping.timeout = 1;
        _ping.pingPeriod = 0.9;
        _timeoutCount = 0;
        self.pingItems = [NSMutableArray arrayWithCapacity:maximumPingTimes];
    }
    return self;
}

- (void)startPing {
    [self.pingItems removeAllObjects];
    self.timeoutCount = 0;
    __weak typeof(self) weakSelf = self;
    [self.ping setupWithBlock:^(BOOL success, NSError *error) {
        if (success) {
            [weakSelf.ping startPinging];
        } else {
            NSLog(@"ping失败");
            PPSPingSummary *summary = [[PPSPingSummary alloc] init];
            summary.status = PPSPingStatusFinished;
            [weakSelf handlSummary:summary];
        }
    }];
}


- (void)cancel {
    [self.ping stop];
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startPing) object:nil];
}

-(void)ping:(PPSPing *)pinger didFailWithError:(NSError *)error {
    PPSPingSummary *summary = [[PPSPingSummary alloc] init];
    summary.status = PPSPingStatusError;
    [self handlSummary:summary];
}

-(void)ping:(PPSPing *)pinger didTimeoutWithSummary:(PPSPingSummary *)summary {
    [self handlSummary:summary];
}

-(void)ping:(PPSPing *)pinger didSendPingWithSummary:(PPSPingSummary *)summary {
    if (_hasStarted) {
        _hasStarted = YES;
        [self handlSummary:summary];
    }
}

-(void)ping:(PPSPing *)pinger didReceiveReplyWithSummary:(PPSPingSummary *)summary {
    [self handlSummary:summary];
}

-(void)ping:(PPSPing *)pinger didFailToSendPingWithSummary:(PPSPingSummary *)summary error:(NSError *)error {
    [self handlSummary:summary];
}

-(void)ping:(PPSPing *)pinger didReceiveUnexpectedReplyWithSummary:(PPSPingSummary *)summary {
    [self handlSummary:summary];
}

- (void)handlSummary:(PPSPingSummary *)summary {
    NSLog(@"ITPing %@", summary);
    if (_pingUseType == PingUseTypeOnce) {
        [self.pingItems addObject:summary];
        if (self.pingItems.count == 5) {
            __block BOOL veryGood = YES;
            [self.pingItems enumerateObjectsUsingBlock:^(PPSPingSummary *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                if (obj.rtt > 100 || obj.status != PPSPingStatusDidReceivePacket) {
                    veryGood = NO;
                }
            }];
            if (veryGood) {
                // 绝对好 停止检测
                NSLog(@"ITPing PingUseTypeOnce 建议 网络环境很好");
                [self.pingItems removeAllObjects];
                _hasStarted = NO;
                self.timeoutCount = 0;
                [self.ping stop];
                return;
            }
        }
        
        if (summary.rtt > 200) {
            self.timeoutCount ++;
        } else if (summary.status != PPSPingStatusDidReceivePacket) {
            self.timeoutCount ++;
        }
        if (self.timeoutCount > (self.holdNum-1)) {
            NSLog(@"ITPing PingUseTypeOnce 建议切换网络 停止 ping ");
            self.timeoutCount = 0;
            _hasStarted = NO;
            [self.ping stop];
            return;
        }
        
        if (summary.sequenceNumber == _maximumPingTimes) {
            // 网络环境良好
            NSLog(@"ITPing PingUseTypeOnce 建议 网络环境良好");
            self.timeoutCount = 0;
            _hasStarted = NO;
            [self.ping stop];
        }
    } else if (_pingUseType == PingUseTypeLoop) {
        if (summary.sequenceNumber == _maximumPingTimes) {
            summary.status = PPSPingStatusFinished;
            _hasStarted = NO;
            [self.ping stop];
            
            // 计算 状态
            __block int threshold = 0;
            [self.pingItems enumerateObjectsUsingBlock:^(PPSPingSummary *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                if (obj.status == PPSPingStatusDidReceivePacket) {
                    if (obj.rtt > 200) {
                        threshold ++;
                    }
                } else {
                    threshold ++;
                }
            }];
            if (threshold > (self.holdNum - 1)) {
                // 网络差
                // 建议切换网络
                NSLog(@"ITPing PingUseTypeLoop 建议切换网络");
            } else {
                NSLog(@"ITPing PingUseTypeLoop 建议网络环境好");
            }
            [self.pingItems removeAllObjects];
            [self performSelector:@selector(startPing) withObject:nil afterDelay:5];
        } else {
            [self.pingItems addObject:summary];
            //--------------------------------------------------//
            if (summary.status == PPSPingStatusFinished) {
                // ping 失败 大概率是没有网络了
                NSLog(@"ITPing PingUseTypeLoop 建议切换网络--");
                _hasStarted = NO;
                [self.ping stop];
                [self.pingItems removeAllObjects];
            }
        }
    }
}


@end
